package com.library.xtype;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import android.content.Context;
import android.util.Log;

import static android.content.ContentValues.TAG;

/**
 * Created by jiangtao on 16/5/21.
 *
 * @author jiang.tao
 * @version 1.0.0
 */
public final class NuwaItemPool {
    private HashMap<Integer, ItemProperty> mHashTypeMapper;
    //注册时候检查索引
    private HashMap<String, ItemProperty> mHashCodeMapper;

    private ItemViewFactory mItemViewFactory;

    private AtomicInteger mAtomicInteger = new AtomicInteger(-1);

    public static final ItemProperty NULLABLE_ITEM_VIEW_PROPERTY = new ItemProperty(NullableItemVO.class,
        NullableIBinder.class, 0);

    public NuwaItemPool() {
        this(10);
    }

    public NuwaItemPool(int initialCapacity) {
        mItemViewFactory = new ItemViewFactoryDefault(this);
        mHashCodeMapper = new LinkedHashMap<>(initialCapacity);
        mHashTypeMapper = new LinkedHashMap<>(initialCapacity);
    }

    public void destory() {
        mAtomicInteger = null;
        mItemViewFactory.destory();
        mHashCodeMapper.clear();
        mHashTypeMapper.clear();
    }

    /**
     * set item view factory
     *
     * @param itemViewFactory itemViewFactory
     */
    public void setItemViewFactory(ItemViewFactory itemViewFactory) {
        if (itemViewFactory == null) {
            return;
        }
        mItemViewFactory = itemViewFactory;
    }

    /**
     * register item view
     *
     * @param voClazz        typeDesc of item view typeDesc
     * @param nuwaItemBinder property
     */
    public <T extends INuwaItemBinder> void register(Class voClazz, Class<T> nuwaItemBinder) {
        if (nuwaItemBinder == null) {
            return;
        }
        //adapter使用int型数据区分type。此处生成type类型是关键
        String hashCode = voClazz.getName();
        ItemProperty itemProperty = mHashCodeMapper.get(hashCode);
        if (itemProperty == null) {
            itemProperty = new ItemProperty(voClazz, nuwaItemBinder);
            int type = mAtomicInteger.incrementAndGet();
            itemProperty.setItemViewType(type);
            mHashTypeMapper.put(type, itemProperty);
            mHashCodeMapper.put(hashCode, itemProperty);
        } else {
            Log.d("XTpe", this.getClass().getSimpleName() + voClazz.getName() + " 同一个class不允许映射到多个 " + nuwaItemBinder
                .getName());
        }
    }

    /**
     * get item view type
     *
     * @param type type of item view type
     * @return type
     */
    public int getItemViewType(Object type) {
        return getProperty(type).getItemViewType();
    }

    /**
     * get item view
     *
     * @param itemType type of item view type
     * @return class of item view
     */
    public Class<? extends INuwaItemBinder> getItemBinder(int itemType) {
        ItemProperty property = mHashTypeMapper.get(itemType);
        if (property == null) {
            property = NULLABLE_ITEM_VIEW_PROPERTY;
        }
        return property.getItemBinderClass();
    }

    private ItemProperty getProperty(Object key) {
        ItemProperty property = mHashCodeMapper.get(key.getClass().getName());
        if (property == null) {
            Log.d(TAG, "getProperty: " + key.getClass().getName() + "类型没有注册到Nuwa");
            property = NULLABLE_ITEM_VIEW_PROPERTY;
        }
        return property;
    }

    /**
     * item type count
     *
     * @return count of item type
     */
    public int getTypeCount() {
        return mHashCodeMapper.size();
    }

    Collection<ItemProperty> getItemPropertys() {
        return mHashTypeMapper.values();
    }

    /**
     * create item view
     *
     * @param context context
     * @param itemVO  item VO
     * @return view
     */
    public INuwaItemBinder createItemView(Context context, Object itemVO) {
        int type = getItemViewType(itemVO);
        return createItemView(context, type);
    }

    /**
     * create item view
     *
     * @param context context
     * @param type    item VO
     * @return view
     */
    public INuwaItemBinder createItemView(Context context, int type) {
        return mItemViewFactory.createItemView(context, type);
    }

}
